<script setup lang="ts">
import { ref, nextTick } from 'vue'
import type { FormInstance } from 'element-plus'
import { ElMessage as message } from 'element-plus'
import { listToTree, traverseTreeArr, sortTreeArr, deepClone } from '@/common/utils'
import { getMenuIdsApi, giveMenusApi } from '@/api/role'
import { getMenuListApi, getSuccessStatus } from '@/api/menu'
import GiveRequestAuth from './giveRequestAuth.vue'

const columns: TableColConfig[] = [
	{
		label: '路由名',
		prop: 'name',
		columnKey: 'name',
		// width: 120,
		align: 'center',
	},
	{
		label: '接口权限',
		prop: 'actions',
		columnKey: 'actions',
		// width: 150,
		align: 'center',
		showOverflowTooltip: true,
		contenRender: ({ row }: any) => {
			if (row.component) return '无需授权'
			return row.actions
		},
	},
	{
		label: '操作',
		prop: 'operation',
		columnKey: 'right',
		align: 'center',
		fixed: 'right',
		resizable: false,
		width: 150,
	},
]
const props = defineProps<{
	editRole: any
}>()
const tableData = ref<MenuType[]>([])
const formInstance = ref<FormInstance | null>(null)

const treeData = ref<MenuType[]>([])
const expandedKeys = ref<IdType[]>([])
const checkedKeys = ref<IdType[]>([])
const halfCheckedKeys = ref<IdType[]>([])
const parentKeys = ref<Set<IdType>>(new Set([]))
const requestAuthDialogVisible = ref(false)
const requestAuthRef = ref()
const editNode = ref({} as MenuType)
const treeRef = ref()

async function init() {
	expandedKeys.value = []
	tableData.value = []
	checkedKeys.value = []
	halfCheckedKeys.value = []
	const checkedIdToActionsMap: { [key: IdType]: string } = {}
	const res = await getMenuIdsApi(props.editRole.id)
	const checkedIds: IdType[] = []
	const halfCheckedIds: IdType[] = []
	if (res.code == getSuccessStatus()) {
		type ResType = { rid: IdType; mid: IdType; actions: string; isHalf: boolean }
		res.data.forEach((v: ResType) => {
			if (!v.isHalf) {
				checkedIds.push(v.mid)
				checkedIdToActionsMap[v.mid] = v.actions
			} else halfCheckedIds.push(v.mid)
		})
	}
	getTreeData(checkedIds, halfCheckedIds, checkedIdToActionsMap)
}

async function getTreeData(checkedIds?: IdType[], halfCheckedIds?: IdType[], checkedIdToActionsMap?: { [key: IdType]: string }) {
	parentKeys.value = new Set([])
	const res = await getMenuListApi({ status: 1 })
	if (res.code == getSuccessStatus()) {
		const tree = listToTree<MenuType>(
			res.data,
			'id',
			'parentId',
			'children',
			false,
			(i) => {
				if (checkedIdToActionsMap && checkedIds?.includes(i.id)) {
					if (checkedIdToActionsMap[i.id]) i.actions = checkedIdToActionsMap[i.id]
					const item = deepClone(i, false)
					delete item.children
					tableData.value.push(item)
				}
			},
			(j) => {
				parentKeys.value.add(j.id)
			}
		) as MenuType
		treeData.value = sortTreeArr<MenuType>([tree], 'sortValue')
		nextTick(() => {
			if (checkedIds && halfCheckedIds) {
				checkedKeys.value = checkedIds
				halfCheckedKeys.value = halfCheckedIds
				expandedKeys.value = [...checkedIds, ...halfCheckedIds]
				treeRef.value?.setCheckedKeys(checkedKeys.value)
			}
		})
	}
}

function handleTreeCheck(node: any, { checkedKeys: _checkedKeys, checkedNodes: _checkedNodes, halfCheckedKeys: _halfCheckedKeys, halfCheckedNodes: _halfCheckedNodes }: any) {
	checkedKeys.value = _checkedKeys
	halfCheckedKeys.value = _halfCheckedKeys
	tableData.value = deepClone(_checkedNodes).map((v: MenuType) => {
		if (v.children) {
			delete v.children
		}
		return v
	})
}

async function formCommit() {
	try {
		await formInstance.value?.validate()
		const checkedIds: IdType[] = []
		checkedKeys.value.forEach((v) => {
			// 提交时有子节点的节点不能为全选，否者会有问题
			if (parentKeys.value.has(v)) halfCheckedKeys.value.push(v)
			else checkedIds.push(v)
		})
		if (!checkedIds.length) {
			message.warning('请勾选角色具备的路由(菜单)节点')
			return
		}
		const idToActionsMap: ObjType = {}
		tableData.value.forEach((v) => {
			idToActionsMap[v.id] = v.actions
		})
		const halfCheckedIds = [...new Set(halfCheckedKeys.value)]
		const idList: { mid: IdType; actions?: string; isHalf: 0 | 1 }[] = []
		checkedIds.forEach((v) => {
			idList.push({ mid: v, actions: idToActionsMap[v], isHalf: 0 })
		})
		halfCheckedIds.forEach((v) => {
			idList.push({ mid: v, isHalf: 1 })
		})
		const res = await giveMenusApi({ rid: props.editRole.id, idList })
		if (res.code) {
			if ((res.code = 200)) {
				return true
			}
		}
	} catch (error) {
		console.log(error)
	}
}

function handleRequestAuth(row: MenuType) {
	editNode.value = row
	requestAuthDialogVisible.value = true
	nextTick(() => {
		requestAuthRef.value.init()
	})
}

async function handleRequestAuthCommit() {
	const actions = await requestAuthRef.value!.formCommit()
	if (actions) {
		traverseTreeArr(
			treeData.value,
			'children',
			(v) => {
				v.actions = actions
			},
			'prop',
			editNode.value.prop
		)
		tableData.value.forEach((v) => {
			if (v.prop == editNode.value.prop) {
				v.actions = actions
			}
		})
	}
}

defineExpose({
	init,
	formCommit,
})
</script>

<template>
	<el-row>
		<el-col :span="5" style="max-height: 580px; overflow: auto">
			<el-tree
				:expand-on-click-node="false"
				:props="{ children: 'children', label: 'title' }"
				node-key="id"
				:data="treeData"
				:default-expanded-keys="expandedKeys"
				show-checkbox
				@check="handleTreeCheck"
				ref="treeRef"
			/>
		</el-col>
		<el-col :span="19" style="padding: 0 10px">
			<my-table border stripe :data="tableData" :columns="columns" style="width: 100%" rowKey="id" :maxHeight="$getDialogBodyMaxHeight()">
				<template #operation="{ row }">
					<el-button type="primary" size="small" @click="handleRequestAuth(row)" :disabled="!row.component ? true : false">页面内权限分配</el-button>
				</template>
			</my-table>
		</el-col>
	</el-row>

	<el-dialog v-model="requestAuthDialogVisible" title="页面内权限分配" width="80%" :modal="false" draggable :close-on-click-modal="false" align-center>
		<el-scrollbar :maxHeight="$getDialogBodyMaxHeight()">
			<div style="padding: 0 10px">
				<GiveRequestAuth ref="requestAuthRef" :edit-node="editNode" />
			</div>
		</el-scrollbar>
		<template #footer>
			<div class="dialog-footer" style="display: flex; justify-content: flex-end">
				<el-button @click="requestAuthDialogVisible = false">取消</el-button>
				<el-button type="primary" @click="handleRequestAuthCommit">确定</el-button>
			</div>
		</template>
	</el-dialog>
</template>
